#pragma once
#include <vector>
#include <unistd.h>
#include <iostream>
#include <assert.h>
#include <string.h>
#include "Log.hpp"
#define DEAFAULT_BUFFER_SIZE 6
class Buffer
{

private:
    std::vector<char> _buffer;
    uint64_t _read_offsert;
    uint64_t _write_offsert;

public:
    Buffer() : _buffer(DEAFAULT_BUFFER_SIZE), _read_offsert(0), _write_offsert(0) {}
    char *Begin() { return &*_buffer.begin(); }
    char *GetReadPostion() { return Begin() + _read_offsert; }
    char *GetWritePostion() { return Begin() + _write_offsert; }
    uint64_t ReadedSize() { return _read_offsert; }
    uint64_t UnWritedSzie() { return _buffer.size() - _write_offsert; }
    uint64_t ReadableSzie() { return _write_offsert - _read_offsert; }
    void EnsureEnoughSize(uint64_t len)
    {
        if (len > UnWritedSzie())
        {
            if (ReadableSzie() + len <= _buffer.size())
            {
                uint64_t rs = ReadableSzie();
                std::copy(GetReadPostion(), GetReadPostion() + rs, Begin());
                _read_offsert = 0;
                _write_offsert = rs;
            }
            else
            {
                _buffer.resize((_write_offsert + len));
            }
        }
    }

    void MoveReadPostion(uint64_t len)
    {
        assert(len <= ReadableSzie());
        _read_offsert += len;
    }
    void MoveWritePostion(uint64_t len)
    {
        EnsureEnoughSize(len);
        _write_offsert += len;
    }
    /// @brief
    /// @param date
    /// @param len
    /// @param isPush 是否移动_write_offsert
    void Write(const char *date, uint64_t len, bool isPush = true)
    {
        if (len == 0)
            return;
        EnsureEnoughSize(len);
        std::copy(date, date + len, GetWritePostion());
        if (isPush)
            MoveWritePostion(len);
    }

    void Write(const std::string &date, bool isPush = true)
    {
        Write(date.c_str(), date.size(), isPush);
    }

    void Write(Buffer &date, bool isPush = true)
    {
        Write(date.ReadAsString(date.ReadableSzie()), isPush);
    }

    /// @brief
    /// @param buffer
    /// @param len
    /// @param isPop 是否移动_read_offsert
    void Read(char *buffer, uint64_t len, bool isPop = false)
    {
        if (len > ReadableSzie())
            len = ReadableSzie();
        std::copy(GetReadPostion(), GetReadPostion() + len, buffer);
        if (isPop)
            MoveReadPostion(len);
    }

    std::string ReadAsString(uint64_t len, bool isPop = false)
    {
        if (len > ReadableSzie())
            len = ReadableSzie();
        std::string ret;
        ret.resize(len);
        Read(&ret[0], len, isPop);
        return ret;
    }

    char *FindCRLF()
    {
        void *ret;
        ret = memchr(GetReadPostion(), '\n', ReadableSzie());
        return (char *)ret;
    }

    std::string GetLine(bool isPop = false)
    {
        char *crlf_pos = FindCRLF();
        if (crlf_pos == nullptr)
            return "";
        uint64_t len = crlf_pos - GetReadPostion() + 1;
        return ReadAsString(len, isPop);
    }
    void Clear()
    {
        _read_offsert = 0;
        _write_offsert = 0;
    }

    void Check()
    {
        using namespace std;
        cout << "_read_offsert:" << _read_offsert << endl;
        cout << "_write_offsert:" << _write_offsert << endl;
        cout << "size:" << _buffer.size() << endl;
        for (int i = _read_offsert; i < ReadableSzie(); i++)
        {
            cout << _buffer[i];
        }
        cout << endl;
    }
};